Day 5

Pitch

  • Top 10 IRC channel: #haskell
  • Reddit: > 10k subscribers
  • Stack Overflow: > 10k questions
  • Learn from smarter people.
helpful
helpful

MONADS

dragon
dragon

Why?

PURE functional. NO side effects. Everything returns, should be deterministic.

Life isn't deterministic. This is why people think it's not useful.

HOW do we deal with LIFE?

  • Side effects in IO
  • Pure everywhere else
brilliant
brilliant

Details

Drawn from, return (opposites)

main :: IO ()
main = do
  putStrLn "quit the program? y/n"
  ans <- getLine
  if ans /= "y" then do
    putStrLn "not quitting"
    main
  else return ()

  -- or
  when (ans /= "y") $ do
    putStrLn "not quitting"
    main

Show Project SETUP

We'll have:

  • Parsing
  • DB
  • WS Server
  • Solver

Values

Next slides are from this excellent tutorial.

Value
Value

Applying Functions

Applying
Applying

Value in context

Context
Context

Applying

Applying functions now depends on context:

Maybe
Maybe
data Maybe a = Just a | Nothing

How to Apply?

Ouch
Ouch

Fmap!

fmap (+3) (Just 2)
Fmap
Fmap

Functors!

Functor is a typeclass:

Functor
Functor

Internals

Functor is just a data type that defines fmap for itself:

fmap
fmap

So we can:

instance Functor Maybe where
    fmap func (Just val) = Just (func val)
    fmap func Nothing = Nothing

fmap (+3) (Just 2)

Visually

Behind the scenes of fmap (+3) (Just 2) we get:

fmapping
fmapping

What About Nothing?

Try to apply (+3) to Nothing and you get:

fnothing
fnothing
ghci>fmap (+3) Nothing
Nothing

Bottoms

Nil is often used as bottom as well as status. In Haskell we still have bottom: undefined.

Because bottom subsumes non-termination, the function isUndefined would have to solve the halting problem and thus cannot exist.

post = Post.find_by_id(1)
if post
  return post.title
else
  return nil
end
fmap (getPostTitle) (findPost 1)
--- or with infix
getPostTitle <$> (findPost 1)

Function to List?

ftolist
ftolist

Because:

instance Functor [] where
    fmap = map

What About Functions?

Normal:

regular
regular

What About?:

applied
applied
fmap (+3) (*2)

How?

instance Functor ((->) r) where
    fmap f g = f . g

As a functor, it's function composition! As a monad:

instance Applicative ((->) r) where
   -- pure :: a -> r -> a
   pure = const

   -- (<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
   (<*>) g f r = g r (f r)

instance Monad ((->) r) where
    -- return :: a -> r -> a
    return = const
    -- (>>=) :: (r -> a) -> (a -> r -> b) -> r -> b
    (>>=) x y z = y (x z) z

Applicatives

Both are wrapped in contexts!

Just 2
Just (+3)

j2 j2

To interact:

j3
j3
ghci>Just (+2) <*> Just 5

More Complicated now

From base:

instance Functor [] where
    fmap = map

instance Applicative [] where
    pure x    = [x]
    fs <*> xs = [f x | f <- fs, x <- xs]
    xs *> ys  = [y | _ <- xs, y <- ys]

instance Monad []  where
    xs >>= f             = [y | x <- xs, y <- f x]
    (>>) = (*>)
    return x            = [x]
    fail _              = []

What is this?

-- So... what is this?
[(*2),(+3)] <*> [1, 2, 3]
answer
answer

Applicatives CAN, Functors CAN'T

Apply function that takes 2 args to 2 wrapped values!

ghci>(+) <$> (Just 5)
Just (+5)
ghci>Just (+5) <$> Just 4
ERRRRR
-- Applicative
ghci>(+) <$> Just 5 <*> Just 4
Just 9
ghci>liftA2 (*) (Just 5) (Just 3)
Just 15

MONADS

We Did

whymonads
whymonads

And

appsagain
appsagain

And

maybeAgain
maybeAgain
half x = if even x
           then Just (x `div` 2)
           else Nothing
valWrap
valWrap

What if feed wrapped?

oucher
oucher

Force it!

Plunger is >>=

plunger
plunger
> Just 3 >>= half
Nothing
> Just 4 >>= half
Just 2
> Nothing >>= half
Nothing
monadBind
monadBind
instance Monad Maybe where
    Nothing >>= func = Nothing
    Just val >>= func  = func val
plungeit
plungeit

Even Simpler

plungeNothing
plungeNothing

We can Chain!

chained
chained
ioMonad
ioMonad
ioMonad2
ioMonad2
ioMonadGo
ioMonadGo
putStrLn
putStrLn
mpipe
mpipe
recap
recap